/*
 * Copyright (c) 2005, 2014 vacoor
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 */
package org.vacoor.nothing.misc.dts.oo.comp;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.vacoor.nothing.common.misc.util.ProcessTree;
import org.vacoor.nothing.common.util.StringUtils;
import org.vacoor.nothing.common.util.Throwables;
import org.vacoor.nothing.misc.dts.oo.util.UnoUtils;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Pattern;

/**
 * OO Server
 * <p/>
 * {@link com.sun.star.comp.helper.Bootstrap#bootstrap()}
 *
 * @author vacoor
 */
public class UnoServerBridge {
    private static final Logger LOG = LoggerFactory.getLogger(UnoServerBridge.class);

    private String ooHome;
    private boolean started;
    private Process process;
    private int pid = -1;
    private final String unoUrl;
    private final String bridgeType;


    /**
     * @param unoUrl
     */
    public UnoServerBridge(String unoUrl, String bridgeType) {
        this.unoUrl = unoUrl;
        this.bridgeType = bridgeType;
    }

    public static UnoServerBridge on(String unoUrl, String bridgeType) {
        return new UnoServerBridge(unoUrl, bridgeType);
    }

    public synchronized void accept() {
        if (started) {
            return;
        }

        started = true;
        // 查找已经存在的服务, windows task 下查看会有 soffice.exe/soffice.bin 但是 bin 其实是 exe 所在进程的
        List<ProcessTree.OSProcess> soffice = ProcessTree.get().query(".*soffice.*" + Pattern.quote(unoUrl + ";" + bridgeType) + ".*");
        int size = soffice.size();
        if (size > 0) {
            if (size > 1) {
                throw new IllegalStateException("不可能吧");
            }
            // 不是自己启动的就不关闭了
            // pid = soffice.get(0).getPid();
            LOG.info("发现与将要启动的 Uno Server Bridge url相同服务已启动, 使用该进程, pid: {}, commandLine: {}", pid, soffice.get(0).getCommandLine());
        } else {
            doStart();
        }
    }

    public synchronized void stop() {
        if (!started) {
            return;
        }
        try {
            if (process != null) {
                process.destroy();
            }

            if (pid != -1) {
                ProcessTree.OSProcess osProcess = ProcessTree.get().get(pid);
                if (osProcess != null) {
                    osProcess.kill();
                }
            }
        } catch (InterruptedException e) {
            throw Throwables.unchecked(e);
        } finally {
            started = false;
            pid = -1;
            process = null;
        }
    }

    private void doStart() {
        ooHome = StringUtils.hasText(ooHome) ? ooHome : UnoUtils.findOOHome();
        LOG.info("OOHOME: {}", ooHome);

        List<String> command = new ArrayList<String>();
        command.add(UnoUtils.getSoffice(ooHome));

        // 已经都改为 --, 为了兼容这里还用 -
        command.add("-nologo");
        command.add("-nodefault");
        command.add("-norestore");
        command.add("-nocrashreport");
        command.add("-nolockcheck");
        command.add("-invisible");
        command.add("-headless");
        command.add("-nofirststartwizard");
        command.add("-accept=" + unoUrl + ";" + bridgeType + ";");

        try {
            LOG.info("启动 UNO Server Bridge ....");

            ProcessBuilder builder = new ProcessBuilder(command);
            process = builder.start();

            String commandLine = null;
            try {
                ProcessTree.OSProcess osProcess = ProcessTree.get().get(process);
                // windows 这里拿到的是 soffice.exe 进程号
                pid = osProcess.getPid();
                commandLine = osProcess.getCommandLine();
            } catch (Exception e) {
                LOG.warn("OSProcess Exception: {}", e);
            }

            LOG.info("启动 UNO Server Bridge Successful, pid: {}, commandLine: {}", pid, commandLine);
        } catch (IOException e) {
            throw Throwables.unchecked(e);
        }
    }
}
